package com.atguigu.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.atguigu.listener.DictListener;
import com.atguigu.mapper.DictMapper;
import com.atguigu.model.cmn.Dict;
import com.atguigu.service.DictService;
import com.atguigu.utils.BeanUtils;
import com.atguigu.vo.cmn.DictEeVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

    /**
     * 根据数据id查询子数据列表
     * value ：缓存名，必填，它指定了你的缓存存放在哪块命名空间
     * keyGenerator ：自定义key规则，自定义生成一个key （格式：类名 + 方法名 + 参数名）
     * @param id
     */
//    @Cacheable(value = "dict", keyGenerator = "keyGenerator")
    @Override
    public List<Dict> findChlidData(Long id) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id",id);
        List<Dict> dictList = baseMapper.selectList(wrapper);//查询上级数据以及子数据列表
        log.info("字典数据：{}", dictList);
        if (CollectionUtils.isEmpty(dictList)) {
            log.warn("字典数据为空，传入id值：{}", id);
            return new ArrayList<>();
        }
        //向list集合每个dict对象中设置hasChildren
        for (Dict dict : dictList) {
            Long dictId = dict.getId();//获取数据字典中每一条记录的id
            //如果一条记录中的id与表中的一条或多条记录的parent_id相等，那么这条记录就存在子数据记录
            boolean isChild = this.isChildren(dictId);
            //设置Dict中hasChildren的值
            dict.setHasChildren(isChild);
        }
        return dictList;
    }

    //判断id下面是否有子节点
    private boolean isChildren(Long id) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id",id);
        Long count = baseMapper.selectCount(wrapper);//查询子节点的个数，没有为0
        // 0>0    1>0
        return count>0;
    }

    @Override
    public void exportData(HttpServletResponse response) {
        try {
            //设置下载信息
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("数据字典", "UTF-8");
            //设置响应标头（标头中带有excel文件名称）
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");

            //查询数据库
            List<Dict> dictList = baseMapper.selectList(null);
            if (CollectionUtil.isEmpty(dictList)) {
                log.warn("当前无字典数据");
                return;
            }
            List<DictEeVo> dictVoList = new ArrayList<>(dictList.size());
            for(Dict dict : dictList) {
                DictEeVo dictVo = new DictEeVo();
                //将每一个dict实例中的属性值复制到dictVo中
                BeanUtils.copyProperties(dict, dictVo, DictEeVo.class);
                dictVoList.add(dictVo);
            }

            //调用方法进行写操作
            EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("数据字典")
                    .doWrite(dictVoList);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导入数据字典
     * value ：缓存名，必填，它指定了你的缓存存放在哪块命名空间
     * allEntries = true: 方法调用后清空所有缓存
     * @param file
     */
//    @CacheEvict(value = "dict", allEntries=true)
    @Override
    public void importDictData(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper))
                    .sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //根据dictcode和value查询数据字典的数据（字典中的name和value类似一个枚举）
    @Override
    public String getDictName(String dictCode, String value) {
        //如果dictCode为空，直接根据value查询（获取最下级节点）
        if(StringUtils.isEmpty(dictCode)) {//查询子节点
            //直接根据value查询
            QueryWrapper<Dict> wrapper = new QueryWrapper<>();
            wrapper.eq("value",value);
            wrapper.last("LIMIT 1");
            Dict dict = baseMapper.selectOne(wrapper);
            return dict.getName();
        } else {//如果dictCode不为空（只有顶级节点和根节点dictCode不为空），根据dictCode和value查询（查询根节点）

            //根据dictcode查询dict对象，得到dict的id值
            //此处的dictCode是一定有值的
            Dict codeDict = this.getDictByDictCode(dictCode);

            //父节点的id是子节点的parent_id
            Long parent_id = codeDict.getId();

            //根据parent_id和value进行查询子节点的值
            Dict finalDict = baseMapper.selectOne(new QueryWrapper<Dict>()
                    .eq("parent_id", parent_id)
                    .eq("value", value));

            return finalDict.getName();
        }
    }

    //根据dictCode获取某个根节点下的下级节点的列表
    @Override
    public List<Dict> findByDictCode(String dictCode) {
        //根据dictcode获取对应根节点的id（对应子节点的parent_id）
        Dict dict = this.getDictByDictCode(dictCode);
        if (dict == null) {
            log.warn("当前字典节点不存在，字典编码：{}", dictCode);
            return new ArrayList<>();
        }
        log.info("findByDictCode，字典id：{}", dict.getId());
        //根据上级id获取子节点
        List<Dict> chlidData = this.findChlidData(dict.getId());
        return chlidData;
    }

    //根据dictCode查询数据字典中的数据（只可使用根节点查询）
    private Dict getDictByDictCode(String dictCode) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("dict_code",dictCode);
        Dict codeDict = baseMapper.selectOne(wrapper);
        return codeDict;
    }

    @Override
    public List<Map<String, Dict>> getDictMapByVal(List<String> valueList) {
        if (CollectionUtil.isEmpty(valueList)) {
            log.warn("查询字段的value为空，valueList：{}", valueList);
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Dict> dictQueryWrapper = Wrappers.lambdaQuery();
        dictQueryWrapper.in(Dict::getValue, valueList);
        List<Dict> dictList = this.getBaseMapper().selectList(dictQueryWrapper);
        if (CollectionUtil.isEmpty(dictList)) {
            log.warn("查询字典数据不存在，valueList：{}", valueList);
        }
        List<Map<String, Dict>> resultList = new ArrayList<>();
        for (Dict dict : dictList) {
            Map<String, Dict> itemMap = new HashMap<>();
            itemMap.put(String.valueOf(dict.getValue()), dict);
            resultList.add(itemMap);
        }
        return resultList;
    }
}

